/*
 * The MIT License
 *
 * Copyright 2012 http://generic-toolset.googlecode.com.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package org.rlpw.swing;

import java.util.Comparator;
import java.util.List;
import javax.swing.JList;
import javax.swing.ListModel;
import javax.swing.event.ListDataListener;

/**
 *
 * @param <T> the type of the elements
 */
public class JOList<T> extends JList<T> implements View<T>, Selectable<T> {

    private Model<T> model;
    private FilteredList<T> flist;
    private ListSelectionAdapter<T> selected;
    private boolean updateLock = false;

    /**
     * 
     * @param m
     */
    public JOList(Model<T> m) {
        flist = new FilteredList<>(this);
        selected = new ListSelectionAdapter<>(this);
        setSelectionModel(selected);
        setDataModel(m);
    }

    /**
     * 
     */
    public JOList() {
        this(new DefaultModel<T>());
    }

    /** {@inheritDoc} */
    @Override
    public void updateView() {

        if (updateLock) {
            return;
        }
        updateLock = true;

        if (flist != null) {
            flist.update();
        }

        List<T> selcted = getSelectModel().getSelected();

        setModel(new ListModel<T>() {

            @Override
            public int getSize() {
                return flist.size();
            }

            @Override
            public T getElementAt(int index) {
                return flist.get(index);
            }

            @Override
            public void addListDataListener(ListDataListener l) {
            }

            @Override
            public void removeListDataListener(ListDataListener l) {
            }
        });


        for (T item : selcted) {
            try {
                getSelectModel().setSelected(item, true);
            } catch (Exception e) {
            }
        }

        updateLock = false;
    }
    
    /** {@inheritDoc} */
    @Override
    public Model<T> getDataModel() {
        return model;
    }

    /** {@inheritDoc} */
    @Override
    public void setDataModel(Model<T> model) {
        if (model == null) {
            throw new IllegalArgumentException("Cannot set a null Model");
        }
        if (this.model != null) {
            this.model.removeView(this);
        }
        model.addView(this);
        this.model = model;
        updateView();
    }

    /** {@inheritDoc} */
    @Override
    public SelectModel<T> getSelectModel() {
        return selected;
    }

    /** {@inheritDoc} */
    @Override
    public Filter<T> getFilter() {
        return flist.getFilter();
    }

    /** {@inheritDoc} */
    @Override
    public void setFilter(Filter<T> filter) {
        flist.setFilter(filter);
    }

    /** {@inheritDoc} */
    @Override
    public void setSorter(Comparator<T> comp) {
        flist.setSorter(comp);
    }

    /** {@inheritDoc} */
    @Override
    public Comparator<T> getSorter() {
        return flist.getSorter();
    }

    /** {@inheritDoc} */
    @Override
    public List<T> getVisibleItems() {
        return flist;
    }
}
